package edu.berkeley.cs160.GroupC;

import java.io.IOException;
import java.util.ArrayList;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import edu.berkeley.cs160.GroupC.songs.Song;

public class PlaySongs extends WorkoutMusicActivity{
	private WorkoutMusicApplication app;
	
	private static ArrayList<Song> library;	
	private ArrayList<Integer> playlistIndex; // Index of songs that is added by User 
	private static ArrayList<Integer> sameActivityLevelSongs = new ArrayList<Integer>(); // Index of same ActivityLevel Songs
	
	private static int activityLevel = 1;
	private static int oldactivity = 0;
	
	private TextView songTitleTextView;
	private TextView songArtistTextView;
	private TextView songAlbumTextView;
	private TextView lockActivityLevelTextView;

	private static final String TAG = "MediaPlayerDemo";
    private static MediaPlayer mediaPlayer;
    private static final int RESOURCES_AUDIO = 3;
    private static long lastActivityChange = System.currentTimeMillis()-20*1000;;
    private static final int BUFFER_TIME = 10 * 1000; //ms
    private static String path;

    private static int counter = 0;
    static Song curSong;
    private static boolean endOfPlaylist = false;
    
	private static String artist;
	private static String title;
	private static String album;
	
	private Button buttonFastForward;
	private Button buttonRewind;
	private Button buttonPlay;
	private Button lockActivityLevel;
	
	private ImageButton buttonRating;
	
	// for accelerometer updates
	private TextView mStepValueView;
	private TextView mPaceValueView;
    private static int mStepValue;
    private static int mPaceValue;
	
	//public Context currentPlaySongContext = getApplicationContext();
	/*
	 ***************** 
	 * ACCELEROMETER *
	 ***************** 
	 */
    
    private IntensityService mService;
	
    protected void onResume() {
    	Log.d("QI", "ON RESUME IS CALLEDDD!!!!!!!!!!!!!");

        app = (WorkoutMusicApplication)getApplication();
        library = app.getCurrentPlaylist();     
        playlistIndex = new ArrayList<Integer>(); 
        Log.d("QI", "LIBRARY SIZE IS " + library.size());
        songTitleTextView = (TextView) findViewById(R.id.PlayerSongTitle);
        songArtistTextView = (TextView) findViewById(R.id.PlayerArtistName);
        songAlbumTextView = (TextView) findViewById(R.id.PlayerAlbumTitle);
        
		buttonRewind = (Button)findViewById(R.id.RewindButton);
		buttonFastForward = (Button)findViewById(R.id.FastForwardButton);
		buttonPlay = (Button)findViewById(R.id.PlayButton);
		lockActivityLevel = (Button)findViewById(R.id.LockActivityLevelButton);
		lockActivityLevelTextView = (TextView) findViewById(R.id.LockTextView);
		buttonRating = (ImageButton)findViewById(R.id.songRate);
        
    	
    	if (mediaPlayer != null){
    		Log.d("QI", "MEDIA PLAYER IS NOT NULL");
    		setActivityLevel(activityLevel);
    	}
    	Log.d("QI", "CALLING SetUpPlaylistIndex");
    	
    	
    	setUpPlaylistIndex();
        
    	Log.v("BACK", "onResume: START");
    	Log.i(TAG, "[ACTIVITY] onResume");
        
   
    	
        mPaceValueView = (TextView) findViewById(R.id.paceDisplay);   
        mStepValueView = (TextView) findViewById(R.id.stepsDisplay);
    
        if (!app.serviceIsRunning) {
        	Log.v("BACK", "onResume: service is not running. start it");
            startIntensityService();
        	app.serviceIsRunning = true;
        }
        
        if (!app.serviceIsBound) {
        	Log.v("BACK", "onResume: service is not bound. bind it");
        	bindIntensityService();
        	app.serviceIsBound = true;
        }
        
        Log.v("BACK", "onResume: call super.onResume");
        super.onResume();
        Log.v("BACK", "onResume: FINISH");
    
    }
	
    protected void onPause() {
        Log.i(TAG, "[ACTIVITY] onPause");
        Log.v("BACK", "onPause: START");
        
        if (app.serviceIsBound) {
        	Log.v("BACK", "onPause: service is bound. unbind it");
            unbindIntensityService();
            app.serviceIsBound = false;
        }
        if (app.serviceIsRunning) {
        	Log.v("BACK", "onPause: service is running. stop it");
        	stopIntensityService();
        	app.serviceIsRunning = false;
        }
        
        Log.v("BACK", "onPause: call super.onPause");
        super.onPause();
        Log.v("BACK", "onPause: END");
    }
    
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = ((IntensityService.StepBinder)service).getService();
            mService.registerCallback(mCallback);
            mService.reloadSettings();
        }
        public void onServiceDisconnected(ComponentName className) {
            mService = null;
        }
    };
    
	private void startIntensityService() {
        if (! app.serviceIsRunning) {
            Log.i(TAG, "[SERVICE] Start");
            
            app.serviceIsRunning = true;
            startService(new Intent(PlaySongs.this,
                    IntensityService.class));
            
        }
	}
	
	private void bindIntensityService() {
	       Log.i(TAG, "[SERVICE] Bind");
	       if(app.mIntent == null){
	    	   app.mIntent = new Intent(PlaySongs.this, IntensityService.class);
	    	   
	       }
	    	
	       bindService(app.mIntent, mConnection, Context.BIND_AUTO_CREATE + Context.BIND_DEBUG_UNBIND);
	}
		
	private void unbindIntensityService() {
        Log.i(TAG, "[SERVICE] Unbind");
        Log.v("BACK", "unbindStepService: start; unbinding service");
        unbindService(mConnection);
        Log.v("BACK", "unbindStepService: end");
	}
	
    private void stopIntensityService() {
        Log.i(TAG, "[SERVICE] Stop");
        if (mService != null) {
            Log.i(TAG, "[SERVICE] stopService");
            stopService(new Intent(PlaySongs.this,
                  IntensityService.class));
        }
     
    }
    
    private void resetValues() {
        if (mService != null && app.serviceIsRunning) {
            mService.resetValues();                    
        }
        else {
            mStepValueView.setText("0");
            mPaceValueView.setText("0");
            app.setCurrentPace(0);
            app.setCurrentSteps(0);
        }
    }
    
    private IntensityService.ICallback mCallback = new IntensityService.ICallback() {
        public void stepsChanged(int value) {
            handler.sendMessage(handler.obtainMessage(WorkoutMusicApplication.STEPS_MSG, value, 0));
        }
        public void paceChanged(int value) {
            handler.sendMessage(handler.obtainMessage(WorkoutMusicApplication.PACE_MSG, value, 0));
        }
 
    };
        
	public void finish() {
		if (app.serviceIsBound) {
        	Log.v("BACK", "onPause: service is bound. unbind it");
            unbindIntensityService();
            app.serviceIsBound = false;
        }
        if (app.serviceIsRunning) {
        	Log.v("BACK", "onPause: service is running. stop it");
        	stopIntensityService();
        	app.serviceIsRunning = false;
        }
		super.finish();
	}
	
	/*
	 * 
	 * END ACCELEROMETER 
	 *********************
	 */
	
	/**********************
	 * PLAY SONGS         *
	 *                    *
	 ********************** 
	 */
	
	/* Main Thread: play songs that have the same activity level
	 * 
	 */	
	private static final int ACT = 1;
	
	private Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			
			switch (msg.what){
				case ACT:
					
					try {
						if (sameActivityLevelSongs.size() > 0) {
							//counter = 0;
							int size = sameActivityLevelSongs.size() ;
							int random = (int) (Math.floor(size * Math.random()) )  ;;
							counter = random;
							
							
							playSongs(sameActivityLevelSongs, counter);
				        }
						
						// if no song matching activityLevel, play songs from playlist.
						else if (sameActivityLevelSongs.size() == 0 && playlistIndex.size() > 0) {
							counter = 0;
							playSongs(playlistIndex, counter);
						}
						else {
				        	finish();
				        }
					}
					catch (Exception e) {
						Log.e(TAG, "Error in main thread " + e.getMessage(), e);
						break;
					}
					
					break;
					
                case WorkoutMusicApplication.STEPS_MSG:
                	
                    mStepValue = (int) msg.arg1;
                    mStepValueView.setText("" + mStepValue);
                    
                    break;
                    
                case WorkoutMusicApplication.PACE_MSG:
                	
                    mPaceValue = msg.arg1;
                    
                    if (mPaceValue <= 0) { 
                        mPaceValueView.setText("0");
                    }
                    
                    else {
                        mPaceValueView.setText("" + (int)mPaceValue);
                        if(mPaceValue < 100){
                        	if(activityLevel == 1 || System.currentTimeMillis() - lastActivityChange < BUFFER_TIME) break;
                        	setActivityLevel(1);
                        	onActivityLevelChange();
                        }
                        else if(mPaceValue <200 ){
                        	if(activityLevel == 2 || System.currentTimeMillis() - lastActivityChange < BUFFER_TIME) break;
                        	setActivityLevel(2);
                        	onActivityLevelChange();
                        }
                        else {
                        	if(activityLevel == 3 || System.currentTimeMillis() - lastActivityChange < BUFFER_TIME) break;
                        	setActivityLevel(3);
                        	onActivityLevelChange();
                        }
                        
                    }
                    
                    break;
                    
				default:
					super.handleMessage(msg);
			}
			
		}
	};

	/* set and get activityLevel methods */
	public int getActivityLevel() {
		return activityLevel;		
	}
	
	public void setActivityLevel(int aLevel) {
		oldactivity = activityLevel;
		activityLevel = aLevel;
		if (oldactivity != aLevel)
			lastActivityChange = System.currentTimeMillis();
	}
	
	/* set up path and play all the songs matching activity level 
	 * or play songs from playlist if no song matching*/
	public void playSongs(ArrayList<Integer> pl, int counter) {
		Log.v("RES", "playSongs: START");
		if (pl != null && pl.size() > 0) {
			int index = pl.get(counter).intValue(); 
	    	curSong = library.get(index);    	
	    	 	
	    	if (mediaPlayer != null) {
	        	mediaPlayer.stop();
	        	mediaPlayer.release();
	        }			        
	    	
	        path = curSong.getFilePath();
	        playAudio(RESOURCES_AUDIO, path, pl);
			setUp(pl);	
		}
		Log.v("RES", "playSongs: END");
	}
	
	/* onCreate */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.rating);
        
        Log.d("QI", "NEW ACTIVITY PLAY SONGS CREATED!!!!");
        
        
        /*	
        app = (WorkoutMusicApplication)getApplication();
        library = app.getCurrentPlaylist();                
        
        songTitleTextView = (TextView) findViewById(R.id.PlayerSongTitle);
        songArtistTextView = (TextView) findViewById(R.id.PlayerArtistName);
        songAlbumTextView = (TextView) findViewById(R.id.PlayerAlbumTitle);
        
		buttonRewind = (Button)findViewById(R.id.RewindButton);
		buttonFastForward = (Button)findViewById(R.id.FastForwardButton);
		buttonPlay = (Button)findViewById(R.id.PlayButton);
		lockActivityLevel = (Button)findViewById(R.id.LockActivityLevelButton);
		lockActivityLevelTextView = (TextView) findViewById(R.id.LockTextView);
		buttonRating = (ImageButton)findViewById(R.id.songRate);
        */
        //if (mediaPlayer != null) setActivityLevel(activityLevel);
        //setUpPlaylistIndex();
	}	
	
	/* 
	 * Adding all the index of the songs that user selects into the playlistIndex ArrayList.	 
	 */
	public void setUpPlaylistIndex(){
		Log.d("QI", "IN setUpPlaylistINDEX");
		new Thread() {
			public void run() {
				try {
					
					for (int i = 0; i < library.size(); i++){
			        	Log.d(TAG, "adding song");			        	
			        		Song curSong = (Song) library.get(i);
				        	if (curSong.isInPlaylist()) {
				        		playlistIndex.add(i);	        		
				        	}			        	
			        }
					Log.d("QI", "PlaylistSize is "+ playlistIndex.size() );
					if (playlistIndex.size( ) > 0) {
						setSongsSameActivityLevel(playlistIndex, activityLevel); //TODO change this constant
					}					
					
				}
				catch (Exception e) {
					// TODO: handle exception
					Log.e(TAG, "error in setUpPlaylistIndex " + e.getMessage(), e);
				}
						
			}				
		}.start();
		
	}
	/* set indexes of all the songs that have the same ActivityLevel 
	 * into the sameActivityLevelSongs 
	 */
	public void setSongsSameActivityLevel(ArrayList<Integer> pl, int activity){
		if (oldactivity == activity) {
			setUp(sameActivityLevelSongs); 
			return;
		}
		sameActivityLevelSongs.clear();
		
		for (Integer songIndex: pl) {
			if (library.get(songIndex.intValue()).getRating() == activity) {
				sameActivityLevelSongs.add(songIndex);				
			}
			
		}
		
		handler.sendMessage(handler.obtainMessage(ACT, 0, 0));
		
	}
	
	public void onActivityLevelChange(){
		new Thread() {
			public void run() {
				try {
					int actLevel = getActivityLevel();
					
					Log.d(TAG, "in onActivityLevelChange(), random is " + actLevel);
					setSongsSameActivityLevel(playlistIndex, actLevel);
					
				}
				catch (Exception e) {
					// TODO: handle exception
					Log.e(TAG, "error in setUpPlaylistIndex " + e.getMessage(), e);
				}
						
			}				
		}.start();
		
	}
	
	/* Setting up Views, Buttons */
	public void setUp(final ArrayList<Integer> pl) {
		
		setUpPlayAndPauseButton();
		
		switch (curSong.getRating()) {
		case 1:

			buttonRating.setImageResource(R.drawable.snail4a);


			break;
		case 2:

			buttonRating.setImageResource(R.drawable.rabbit4a);

			break;	
		case 3:
			buttonRating.setImageResource(R.drawable.cheetah4a);

			
			break;	
		default:
			break;
		}
		
		artist = curSong.getArtist();
		album = curSong.getAlbum();
		title = curSong.getTitle();

		songTitleTextView.setText(title);
		songArtistTextView.setText(artist);
		songAlbumTextView.setText(album);
		
		// ChgActivityLevel button:
		lockActivityLevel.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				Log.d(TAG, "error in setUpPlaylistIndex " );
				//onActivityLevelChange();
			    
		        if (!app.serviceIsRunning) {
		        	Log.v("BACK", ": service is not running. start it");
		        	lockActivityLevelTextView.setText("Click to lock this activity level");
		        	lockActivityLevel.setBackgroundResource(R.drawable.unlock);
		            startIntensityService();
		        	app.serviceIsRunning = true;
		        }else{
		        	lockActivityLevelTextView.setText("unlock");
		        	stopIntensityService();
		        	app.serviceIsRunning = false;
		        	lockActivityLevel.setBackgroundResource(R.drawable.lock);
		        }
		        
		        if (!app.serviceIsBound) {
		        	Log.v("BACK", "onResume: service is not bound. bind it");
		        	bindIntensityService();
		        	app.serviceIsBound = true;
		        }else{
		            unbindIntensityService();
		            app.serviceIsBound = false;	
		        	
		        }
		    
		        
			}
		});
		
		// PlayButton: change to Pause when it is hit if music is playing
		buttonPlay.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				if (mediaPlayer!=null) {
					if(mediaPlayer.isPlaying()){
						mediaPlayer.pause();
						setUpPlayAndPauseButton();
					}
					else {
						mediaPlayer.start();
						setUpPlayAndPauseButton();
					}
				}
					
				if(mediaPlayer == null && endOfPlaylist==true){
					playSongs(pl, 0);
				}
			}
		});
		
		buttonRewind.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				try {
					if ((counter - 1) >= 0){
						counter--;
						playSongs(pl, counter);
						updateSongDisplayInfo(pl);
						Log.d(TAG, "counter is " + counter);
					}
					else {
						playSongs(pl, counter);
					}
					
				}
				catch (Exception e) {
					Log.e(TAG, "Rewind error " + e.getMessage(), e);
				}
				
			}
		});
		
		buttonFastForward.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				try {
					if ((counter + 1) < pl.size()){
						counter++;
						playSongs(pl, counter);
						updateSongDisplayInfo(pl);
					}
					else {
						counter = 0;
						playSongs(pl, counter);
					}
				}
				catch (Exception e) {
					Log.e(TAG, "Fastforward error "+ e.getMessage(), e);
				}
				
			}
		});
		
		buttonRating.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				Toast.makeText(PlaySongs.this, "Long press to change rating!", Toast.LENGTH_SHORT).show();
			}
			
		});
		
		buttonRating.setOnLongClickListener(new View.OnLongClickListener() {
			public boolean onLongClick(View v) {
				
				app.setNewSongAdded(curSong);
				Intent intent = new Intent(PlaySongs.this, Rating.class);
				startActivity(intent);
				
				return true;
			}
		});
	}
	
	public void updateSongDisplayInfo(ArrayList<Integer> pl){
		int index = pl.get(counter).intValue(); 
    	curSong = library.get(index);
		
		artist = curSong.getArtist();
		title = curSong.getAlbum();
		songTitleTextView = (TextView)findViewById(R.id.PlayerSongTitle);
        songArtistTextView = (TextView)findViewById(R.id.PlayerArtistName);
        songTitleTextView.setText(title);
		songArtistTextView.setText(artist);
		
		setUpPlayAndPauseButton();
	}
	
	public void setUpPlayAndPauseButton() {
		if (mediaPlayer != null) {
			if (mediaPlayer.isPlaying()) {
				buttonPlay.setBackgroundResource(R.drawable.pause3);
			}
			else{
				buttonPlay.setBackgroundResource(R.drawable.play3);
			}
		}
		else {
			Log.v("RES", "setUpPlayAndPauseButton: mediaPlayer == null");
		}
	}
	
	public void playAudio(Integer media, String songPath, final ArrayList<Integer> pl) {
		
	    try {
	        switch (media) {
	            case RESOURCES_AUDIO:
	                /**
	                 * TODO: Upload a audio file to res/raw folder and provide
	                 * its resid in MediaPlayer.create() method.
	                 */
	            	mediaPlayer = new MediaPlayer();
		        	mediaPlayer.reset();
		        	mediaPlayer.setDataSource(path);
		            mediaPlayer.prepare();
		            mediaPlayer.start();
 
	                mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
						
						@Override
						public void onCompletion(MediaPlayer mp) {
							// TODO Auto-generated method stub
							Log.d(TAG, "In onCompletion(), done playing music: ") ;
							counter++;
							if (pl.size() > counter){
								playNewSong(counter, pl);
							}
							else{
								counter=0;
							}
							int index = pl.get(counter).intValue(); 
				        	curSong = library.get(index);
							setUp(pl);
						}
							
					});            
	                
	                Log.d(TAG, "Done Playing " + songPath) ;
	                
	
	        }
	        //tx.setText("Playing audio...");
	
	    } catch (Exception e) {
	        Log.e(TAG, "error: " + e.getMessage(), e);
	    }
	
	}
	
	public void playNewSong(int songNum, ArrayList<Integer> pl){
		if (songNum >= pl.size()) {
			mediaPlayer.stop();
			mediaPlayer.release();
			endOfPlaylist = true;
		}
		else{
			try
		    {   
		        mediaPlayer.reset();
		        int index = pl.get(counter).intValue(); 
	        	curSong = library.get(index);
		        
		       
		        path = curSong.getFilePath();
		        mediaPlayer.setDataSource(path);
		        mediaPlayer.prepare();
		        mediaPlayer.start();
		        
		    }
		    catch (IllegalArgumentException e) {
		        Log.e(TAG, "Unable to play audio queue do to exception: " + e.getMessage(), e);
		    }
		    catch (IllegalStateException e) {
		        Log.e(TAG, "Unable to play audio queue do to exception: " + e.getMessage(), e);
		    }
		    catch (IOException e) {
		        Log.e(TAG, "Unable to play audio queue do to exception: " + e.getMessage(), e);
		    }
		}
	}
	
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			
	    	try {
				if (endOfPlaylist == false) {
		    		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
		    			//mediaPlayer.stop();
		    			//mediaPlayer.release();
		    		}
		    	}
				else {
				}
				finish();
				return true;
			}
			catch (Exception e) {
				Log.e("BACK", "Pressing Back button error "+e.getMessage() + " Cause: " + e.getCause(), e);
				Log.e("BACK", e.toString());
			}
			
	    }
		
	    return super.onKeyDown(keyCode, event);
	}
	
	
	
}
